home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 5
/
Aminet 5 - March 1995.iso
/
Aminet
/
game
/
role
/
Ang261Lib.lha
/
src
/
creature.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-22
|
95KB
|
3,337 lines
/*
* creature.c: handle monster movement and attacks
*
* Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
*
* This software may be copied and distributed for educational, research, and
* not for profit purposes provided that this copyright and statement are
* included in all such copies.
*/
#include "constant.h"
#include "monster.h"
#include "config.h"
#include "types.h"
#include "externs.h"
#ifdef USG
#ifndef ATARIST_MWC
#include <string.h>
#else
char *strcat();
char *strcpy();
#endif
#else
#include <strings.h>
#endif
/* Lets do all prototypes correctly.... -CWS */
#ifndef NO_LINT_ARGS
#ifdef __STDC__
static int check_mon_lite(int, int);
static void get_moves(int, int *);
static int monster_critical(int, int, int);
static void make_attack(int);
static void make_move(int, int *, int32u *);
static void mon_cast_spell(int, int *);
static void mon_move(int, int32u *);
static void shatter_quake(int, int);
static void br_wall(int, int);
#else
static int check_mon_lite();
static void get_moves();
static int monster_critical();
static void make_attack();
static void make_move();
static void mon_cast_spell();
static void mon_move();
static void shatter_quake();
static void br_wall();
#endif
#endif
/* Updates screen when monsters move about -RAK- */
void
update_mon(monptr)
int monptr;
{
register int flag;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
#ifdef ATARIST_MWC
int32u holder;
#endif
m_ptr = &m_list[monptr];
flag = FALSE;
if ((m_ptr->cdis <= MAX_SIGHT) &&
(!(py.flags.status & PY_BLIND) || py.flags.telepathy) &&
(panel_contains((int)m_ptr->fy, (int)m_ptr->fx))) {
/* Wizard sight. */
if (wizard)
flag = TRUE;
/* if not mindless, telepathy sees -CWS */
if (py.flags.telepathy) {
char c = c_list[m_ptr->mptr].cchar;
const char *n = c_list[m_ptr->mptr].name;
if (strchr("EMXgjvz.",c));
/* don't show these ever (elementals & golems & vorticies & xorns
* "minds" are too different) -CFT */
else if (strchr("FKaclt",c)) {
if (randint(5)==1)
flag = TRUE;
/* once in a while we see these almost mindless insects... -CFT */
} else if (c=='S' && strncmp(n, "Drider", 6) &&
!(c_list[m_ptr->mptr].cdefense & UNIQUE)) {
if (randint(5)==1) flag = TRUE;
/* once in a while show spiders, scops. But DO show drider,
* Shelob, and Ungol. -CFT */
} else if (c=='m' && strncmp(n, "Death", 5));
/* don't show any molds, except the Death mold -CFT */
else if (c=='s' && !strstr(n, "ruj") &&
strncmp(n, "Cantor", 6));
/* don't show skeletons, but DO show druj and Cantoras -CFT */
else if (c=='i' && strncmp(n, "Blue", 4));
/* don't show icky things, except Blue icky things.. -CFT */
else if (c=='w' && strncmp(n, "Were", 4) && strncmp(n, "Gian", 4)) {
if (randint(5)==1) flag = TRUE;
/* occas. show worms, except Purple worms and Wereworms -CFT */
} else if (c==',' && strncmp(n, "Magic", 5));
/* don't show mushrooms, except magic 'shrooms -CFT */
else if (!(c_list[m_ptr->mptr].cdefense & MINDLESS))
flag = TRUE;
/* if not mindless, they show up -CWS */
}
/* Normal sight. */
if (los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) {
c_ptr = &cave[m_ptr->fy][m_ptr->fx];
#ifdef GROSS_HACK
/* Try to debug invis monsters...this is not 'fixed', per se
* but it will correct the observed problem and also give me
* a chance to trap the thing with a debugger. -CWS
*******
* This should no longer be necessary, but it's harmless -CWS
*/
if (c_ptr->cptr != monptr) {
char BUF[100];
sprintf(BUF, "Help! cptr = %d / monptr = %d, x = %d, y = %d",
c_ptr->cptr, monptr, m_ptr->fx, m_ptr->fy);
if (wizard)
msg_print(BUF);
c_ptr->cptr = monptr;
}
#endif /* GROSS_HACK */
r_ptr = &c_list[m_ptr->mptr];
/* moved here to allow infra to see invis -CFT */
if ((py.flags.see_infra > 0) &&
(m_ptr->cdis <= py.flags.see_infra)) {
if (NO_INFRA & r_ptr->cdefense) /* changed to act sensibly -CFT */
c_recall[m_ptr->mptr].r_cdefense |= NO_INFRA;
else
flag = TRUE; /* only can see if not NO_INFRA... */
}
if (c_ptr->pl || c_ptr->tl ||
(find_flag && m_ptr->cdis <= light_rad && player_light)) {
#ifdef ATARIST_MWC
holder = CM_INVISIBLE;
if ((holder & r_ptr->cmove) == 0)
#else
if ((CM_INVISIBLE & r_ptr->cmove) == 0)
#endif
flag = TRUE;
else if (py.flags.see_inv) {
flag = TRUE;
#ifdef ATARIST_MWC
c_recall[m_ptr->mptr].r_cmove |= holder;
#else
c_recall[m_ptr->mptr].r_cmove |= CM_INVISIBLE;
#endif
}
}
}
}
/* Light it up. */
if (flag) {
#ifdef TC_COLOR
if (!no_color_flag) /* don't waste time if no color -CFT */
lite_spot((int)m_ptr->fy, (int)m_ptr->fx);
/* redraw, even if lit, so MHD's change color -CFT */
#endif
if (!m_ptr->ml) {
disturb(1, 0);
m_ptr->ml = TRUE;
lite_spot((int)m_ptr->fy, (int)m_ptr->fx);
screen_change = TRUE; /* notify inven_command */
}
}
/* Turn it off. */
else if (m_ptr->ml) {
m_ptr->ml = FALSE;
lite_spot((int)m_ptr->fy, (int)m_ptr->fx);
screen_change = TRUE; /* notify inven_command */
}
}
/* Given speed, returns number of moves this turn. -RAK- */
/* NOTE: Player must always move at least once per iteration,
* a slowed player is handled by moving monsters faster
*
* monnum = index in m_list[] now passed in, so (turn+monnum) can
* be used to vary when monsters move. -CFT
*/
int
movement_rate(monnum)
int monnum;
{
register int ps, ms, tm, i;
ps = 1 - py.flags.speed; /* this makes normal = 1, fast = 2,
* v.fast = 3, slow = 0, v.slow = -1 -CFT */
ms = m_list[monnum].cspeed;
i = (int)(turn & 0xFF) + (int)monnum; /* 0xFF to prevent negative values -CFT */
if (ps == ms)
return 1; /* same spd as player -CFT */
if (ps<1 && ms<1) { /* both slow, swap "reciprocals" -CFT */
tm = 2 - ps;
ps = 2 - ms;
ms = tm;
}
if (ps < 1) /* then mon must be fast, or above would */
return ms * (2 - ps); /* have happened -CFT */
if (ms<1) /* then player fast... move once in a while -CFT */
return !(i % (ps * (2 - ms)));
/* player faster.
* This formula is not intuitive, but it effectively uses the turn counter
* (offset by the monster index, so not every monster moves at same time)
* to compute factional parts of movement ratios.. so that a monster 2/3 the
* player's spd will move twice every 3 turns. An earlier version of this
* equation performed the same result on average, but it was prone to "clumps"
* of speed... if the player was spd 4, and the monster spd 2, then for each
* 4 turn cycle, the monster would move 0,0,1,1. This equation will result
* in 0,1,0,1, which is better. -CFT
*/
if (ps>ms)
return (((i*ms) % ps) < ms);
if (!(tm = (ms % ps))) /* divides evenly, simple case -CFT */
return (ms / ps);
/* Like the player-faster formula, this is NOT intuitive. However, it
* effectively uses the turn counter & monster index to decide when a
* monster should get an "extra" move. It also prevents "clumps". -CFT
*/
return ((ms / ps) + (((i*tm) % ps) < tm));
}
/* Makes sure a new creature gets lit up. -CJS- */
static int
check_mon_lite(y, x)
int y, x;
{
register int monptr;
monptr = cave[y][x].cptr;
if (monptr <= 1)
return FALSE;
else {
update_mon(monptr);
return m_list[monptr].ml;
}
}
/* Choose correct directions for monster movement -RAK- */
static void
get_moves(monptr, mm)
int monptr;
register int *mm;
{
int y, ay, x, ax, move_val;
y = m_list[monptr].fy - char_row;
x = m_list[monptr].fx - char_col;
/* lvl 1..15 always afraid, 16..22 some, based on maxhp %8 :
* lvl 16 7 of 8 monsters afraid [ this is for a 50th ]
* lvl 22 1 of 8 monsters afraid [ level player, lower ]
* lvl 23++ no afraid monsters [ level=less afraid m. ]
*/
if (((int16)(py.misc.lev - 34 - c_list[(m_list[monptr]).mptr].level +
((m_list[monptr].maxhp) % 8)) > 0)
|| m_list[monptr].monfear) { /* Run away! Run away! -DGK */
y = (-y); /* FIXME: make monsters running away more intelligent */
x = (-x);
}
if (y < 0) {
move_val = 8;
ay = (-y);
} else {
move_val = 0;
ay = y;
}
if (x > 0) {
move_val += 4;
ax = x;
} else
ax = (-x);
/* this has the advantage of preventing the diamond maneuvre, also faster */
if (ay > (ax << 1))
move_val += 2;
else if (ax > (ay << 1))
move_val++;
switch (move_val) {
case 0:
mm[0] = 9;
if (ay > ax) {
mm[1] = 8;
mm[2] = 6;
mm[3] = 7;
mm[4] = 3;
} else {
mm[1] = 6;
mm[2] = 8;
mm[3] = 3;
mm[4] = 7;
}
break;
case 1:
case 9:
mm[0] = 6;
if (y < 0) {
mm[1] = 3;
mm[2] = 9;
mm[3] = 2;
mm[4] = 8;
} else {
mm[1] = 9;
mm[2] = 3;
mm[3] = 8;
mm[4] = 2;
}
break;
case 2:
case 6:
mm[0] = 8;
if (x < 0) {
mm[1] = 9;
mm[2] = 7;
mm[3] = 6;
mm[4] = 4;
} else {
mm[1] = 7;
mm[2] = 9;
mm[3] = 4;
mm[4] = 6;
}
break;
case 4:
mm[0] = 7;
if (ay > ax) {
mm[1] = 8;
mm[2] = 4;
mm[3] = 9;
mm[4] = 1;
} else {
mm[1] = 4;
mm[2] = 8;
mm[3] = 1;
mm[4] = 9;
}
break;
case 5:
case 13:
mm[0] = 4;
if (y < 0) {
mm[1] = 1;
mm[2] = 7;
mm[3] = 2;
mm[4] = 8;
} else {
mm[1] = 7;
mm[2] = 1;
mm[3] = 8;
mm[4] = 2;
}
break;
case 8:
mm[0] = 3;
if (ay > ax) {
mm[1] = 2;
mm[2] = 6;
mm[3] = 1;
mm[4] = 9;
} else {
mm[1] = 6;
mm[2] = 2;
mm[3] = 9;
mm[4] = 1;
}
break;
case 10:
case 14:
mm[0] = 2;
if (x < 0) {
mm[1] = 3;
mm[2] = 1;
mm[3] = 6;
mm[4] = 4;
} else {
mm[1] = 1;
mm[2] = 3;
mm[3] = 4;
mm[4] = 6;
}
break;
case 12:
mm[0] = 1;
if (ay > ax) {
mm[1] = 2;
mm[2] = 4;
mm[3] = 3;
mm[4] = 7;
} else {
mm[1] = 4;
mm[2] = 2;
mm[3] = 7;
mm[4] = 3;
}
break;
}
}
static int
monster_critical(dice, sides, dam)
int dice, sides, dam;
{
int total = dice * sides;
int max = 0;
if (dam == total && dam > 20)
max = 1;
if ((dam > (19 * total) / 20) && ((dam < 20) ? randint(20) == 1 : TRUE)) {
if (dam > 20)
while (randint(50) == 1)
max++;
if (dam > 45)
return 6 + max;
if (dam > 33)
return 5 + max;
if (dam > 25)
return 4 + max;
if (dam > 18)
return 3 + max;
if (dam > 11)
return 2 + max;
return 1 + max;
}
return 0;
}
/* Make an attack on the player (chuckle.) -RAK- */
static void
make_attack(monptr)
int monptr;
{
int attype, adesc, adice, asides;
int i, j, damage, flag, attackn, notice, visible;
int shatter = FALSE;
int CUT = FALSE, STUN = FALSE;
int32 gold;
attid *attstr, *attstr_orig;
vtype cdesc, tmp_str, ddesc;
register creature_type *r_ptr;
monster_type *m_ptr;
register struct misc *p_ptr;
register struct flags *f_ptr;
register inven_type *i_ptr;
int8u blinked = 0; /* flag to see if blinked away (after
* steal) -CFT */
if (death) /* don't beat a dead body! */
return;
m_ptr = &m_list[monptr];
r_ptr = &c_list[m_ptr->mptr];
if (r_ptr->cdefense & DESTRUCT)
shatter = TRUE;
if (!m_ptr->ml)
(void)strcpy(cdesc, "It ");
else {
if (c_list[m_ptr->mptr].cdefense & UNIQUE)
(void)sprintf(cdesc, "%s ", r_ptr->name);
else
(void)sprintf(cdesc, "The %s ", r_ptr->name);
}
/* For "DIED_FROM" string */
if (r_ptr->cdefense & UNIQUE)
(void)sprintf(ddesc, "%s", r_ptr->name);
else if (is_a_vowel(r_ptr->name[0]))
(void)sprintf(ddesc, "an %s", r_ptr->name);
else
(void)sprintf(ddesc, "a %s", r_ptr->name);
/* End DIED_FROM */
attackn = 0;
attstr = r_ptr->damage;
attstr_orig = attstr;
/* if has no attacks (*attstr starts off 0), still loop once to accumulate
* notices that it has no attacks - dbd
*/
while ((*attstr != 0 || attstr == attstr_orig) && !death && !blinked) {
attype = monster_attacks[*attstr].attack_type;
adesc = monster_attacks[*attstr].attack_desc;
adice = monster_attacks[*attstr].attack_dice;
asides = monster_attacks[*attstr].attack_sides;
attstr++;
flag = FALSE;
if (((py.flags.protevil > 0) && (r_ptr->cdefense & EVIL) &&
((py.misc.lev + 1) > r_ptr->level)) &&
(randint(100) + (py.misc.lev) > 50))
/* Random (100) + level > 50 chance for stop any attack added */
{
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= EVIL;
attype = 99;
adesc = 99;
}
p_ptr = &py.misc;
switch (attype) {
case 1: /* Normal attack */
if (test_hit(60, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 2: /* Lose Strength */
if (test_hit(-3, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 3: /* Confusion attack */
if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 4: /* Fear attack */
if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 5: /* Fire attack */
if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 6: /* Acid attack */
if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 7: /* Cold attack */
if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 8: /* Lightning attack */
if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 9: /* Corrosion attack */
if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 10: /* Blindness attack */
if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 11: /* Paralysis attack */
if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 12: /* Steal Money */
if ((test_hit(5, (int)r_ptr->level, 0, (int)py.misc.lev,
CLA_MISC_HIT))
&& (py.misc.au > 0))
flag = TRUE;
break;
case 13: /* Steal Object */
if ((test_hit(2, (int)r_ptr->level, 0, (int)py.misc.lev,
CLA_MISC_HIT))
&& (inven_ctr > 0))
flag = TRUE;
break;
case 14: /* Poison */
if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 15: /* Lose dexterity */
if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 16: /* Lose constitution */
if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 17: /* Lose intelligence */
if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 18: /* Lose wisdom */
if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 19: /* Lose experience */
if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 20: /* Aggravate monsters */
flag = TRUE;
break;
case 21: /* Disenchant */
if (test_hit(20, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 22: /* Eat food */
if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 23: /* Eat light */
if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT))
flag = TRUE;
break;
case 24: /* Eat charges */
if ((test_hit(15, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT)) &&
(inven_ctr > 0)) /* check to make sure an object exists */
flag = TRUE;
break;
case 25: /* Drain all stats */
if ((test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac,
CLA_MISC_HIT)))
flag = TRUE;
break;
case 99:
flag = TRUE;
break;
case 0: /* Monster has no physical attacks - dbd */
flag = TRUE;
break;
default:
break;
}
/* can not strcat to cdesc because the creature may have multiple attacks */
if (flag) {
disturb(1, 0);
(void)strcpy(tmp_str, cdesc);
CUT = STUN = FALSE;
switch (adesc) {
case 1:
msg_print(strcat(tmp_str, "hits you."));
CUT = TRUE;
STUN = TRUE;
break;
case 2:
msg_print(strcat(tmp_str, "bites you."));
CUT = TRUE;
break;
case 3:
msg_print(strcat(tmp_str, "claws you."));
CUT = TRUE;
break;
case 4:
msg_print(strcat(tmp_str, "stings you."));
break;
case 5:
msg_print(strcat(tmp_str, "touches you."));
break;
case 6:
msg_print(strcat(tmp_str, "kicks you."));
break;
case 7:
msg_print(strcat(tmp_str, "gazes at you."));
break;
case 8:
msg_print(strcat(tmp_str, "breathes on you."));
break;
case 9:
msg_print(strcat(tmp_str, "spits on you."));
break;
case 10:
msg_print(strcat(tmp_str, "makes a horrible wail."));
break;
case 11:
msg_print(strcat(tmp_str, "embraces you."));
break;
case 12:
msg_print(strcat(tmp_str, "crawls on you."));
break;
case 13:
msg_print(strcat(tmp_str, "releases a cloud of spores."));
break;
case 14:
msg_print(strcat(tmp_str, "begs you for money."));
break;
case 15:
msg_print("You've been slimed!");
break;
case 16:
msg_print(strcat(tmp_str, "crushes you."));
break;
case 17:
msg_print(strcat(tmp_str, "tramples you."));
STUN = TRUE;
break;
case 18:
msg_print(strcat(tmp_str, "drools on you."));
break;
case 19:
switch (randint(9)) {
case 1:
msg_print(strcat(tmp_str, "insults you!"));
break;
case 2:
msg_print(strcat(tmp_str, "insults your mother!"));
break;
case 3:
msg_print(strcat(tmp_str, "gives you the finger!"));
break;
case 4:
msg_print(strcat(tmp_str, "humiliates you!"));
break;
case 5:
msg_print(strcat(tmp_str, "wets on your leg!"));
break;
case 6:
msg_print(strcat(tmp_str, "defiles you!"));
break;
case 7:
msg_print(strcat(tmp_str, "dances around you!"));
break;
case 8:
msg_print(strcat(tmp_str, "makes obscene gestures!"));
break;
case 9:
msg_print(strcat(tmp_str, "moons you!!!"));
break;
}
break;
case 20:
msg_print(strcat(tmp_str, "butts you."));
STUN = TRUE;
break;
case 21:
msg_print(strcat(tmp_str, "charges you."));
STUN = TRUE;
break;
case 22:
msg_print(strcat(tmp_str, "engulfs you."));
break;
case 23:
switch (randint(5)) {
case 1:
msg_print(strcat(tmp_str, "wants his mushrooms back. "));
break;
case 2:
msg_print(strcat(tmp_str, "tells you to get off his land. "));
break;
case 3:
msg_print(strcat(tmp_str, "looks for his dogs. "));
break;
case 4:
msg_print(strcat(tmp_str, "says 'Did you kill my Fang?' "));
break;
case 5:
msg_print(strcat(tmp_str,
"asks 'Do you want to buy any mushrooms?' "));
break;
}
break;
case 99:
msg_print(strcat(tmp_str, "is repelled."));
break;
default: /* no message for case 0 because no attacks - dbd */
break;
}
notice = TRUE;
/*
* always fail to notice attack if creature invisible, set notice and
* visible here since creature may be visible when attacking and then
* teleport afterwards (becoming effectively invisible)
*/
if (!m_ptr->ml) {
visible = FALSE;
notice = FALSE;
} else
visible = TRUE;
damage = damroll(adice, asides);
switch (attype) {
case 0: /* No physical attacks */
/* put something here to notice if monster *has* no physical attacks -CWS */
if (!randint(10))
notice = TRUE;
break;
case 1: /* Normal attack */
/* round half-way case down */
damage -= ((((((p_ptr->pac + p_ptr->ptoac) > 150) ? 150 :
(p_ptr->pac + p_ptr->ptoac)) * 3) / 4) * damage) / 200;
take_hit(damage, ddesc);
if ((damage > 23) && shatter)
shatter_quake(m_ptr->fy, m_ptr->fx);
break;
case 2: /* Lose Strength */
take_hit(damage, ddesc);
if (py.flags.sustain_str)
msg_print("You feel weaker for a moment, but it passes.");
else if (randint(2) == 1) {
msg_print("You feel weaker.");
(void)dec_stat(A_STR);
} else
notice = FALSE;
break;
case 3: /* Confusion attack */
f_ptr = &py.flags;
take_hit(damage, ddesc);
if ((!py.flags.confusion_resist) && (!py.flags.chaos_resist)) {
if (randint(2) == 1) {
if (f_ptr->confused < 1) {
msg_print("You feel confused.");
f_ptr->confused += randint((int)r_ptr->level);
} else
notice = FALSE;
f_ptr->confused += 3;
} else
notice = FALSE;
}
break;
case 4: /* Fear attack */
f_ptr = &py.flags;
take_hit(damage, ddesc);
if (player_saves() || (py.misc.pclass == 1 && randint(3) == 1)
|| py.flags.fear_resist)
msg_print("You stand your ground!");
else if (f_ptr->afraid < 1) {
msg_print("You are suddenly afraid!");
f_ptr->afraid += 3 + randint((int)r_ptr->level);
} else {
f_ptr->afraid += 3;
notice = FALSE;
}
break;
case 5: /* Fire attack */
msg_print("You are enveloped in flames!");
fire_dam(damage, ddesc);
break;
case 6: /* Acid attack */
msg_print("You are covered in acid!");
acid_dam(damage, ddesc);
break;
case 7: /* Cold attack */
msg_print("You are covered with frost!");
cold_dam(damage, ddesc);
break;
case 8: /* Lightning attack */
msg_print("Lightning strikes you!");
light_dam(damage, ddesc);
break;
case 9: /* Corrosion attack */
msg_print("A stinging red gas swirls about you.");
corrode_gas(ddesc);
take_hit(damage, ddesc);
break;
case 10: /* Blindness attack */
f_ptr = &py.flags;
take_hit(damage, ddesc);
if (!py.flags.blindness_resist) {
if (f_ptr->blind < 1) {
f_ptr->blind += 10 + randint((int)r_ptr->level);
msg_print("Your eyes begin to sting.");
} else {
f_ptr->blind += 5;
notice = FALSE;
}
}
break;
case 11: /* Paralysis attack */
f_ptr = &py.flags;
take_hit(damage, ddesc);
if (player_saves())
msg_print("You resist the effects!");
else if (f_ptr->paralysis < 1) {
if (f_ptr->free_act)
msg_print("You are unaffected.");
else {
f_ptr->paralysis = randint((int)r_ptr->level) + 3;
msg_print("You are paralysed.");
}
} else
notice = FALSE;
break;
case 12: /* Steal Money */
if ((py.flags.paralysis < 1) &&
(randint(168) < py.stats.use_stat[A_DEX]))
/* immune to steal at 18/150 */
msg_print("You quickly protect your money pouch!");
else { /* make this more sane.... -CWS */
vtype t1;
gold = (p_ptr->au / 10) + randint(25);
if (gold > 5000)
gold = 2000 + randint(1000) + (p_ptr->au / 20);
if (gold > p_ptr->au)
gold = p_ptr->au;
p_ptr->au -= gold;
msg_print("Your purse feels lighter.");
sprintf(t1, "%ld coin%s stolen!", (long)gold,
(gold > 1L) ? "s were" : " was");
msg_print(t1);
prt_gold();
}
if (randint(2) == 1) {
msg_print("There is a puff of smoke!");
blinked = 1; /* added -CFT */
teleport_away(monptr, MAX_SIGHT);
}
break;
case 13: /* Steal Object */
if ((py.flags.paralysis < 1) &&
(randint(168) < py.stats.use_stat[A_DEX]))
/* immune to steal at 18/150 change */
msg_print("You grab hold of your backpack!");
else {
vtype t1, t2;
i = randint(inven_ctr) - 1;
if ((inventory[i].tval >= TV_MIN_WEAR) &&
(inventory[i].tval <= TV_MAX_WEAR) &&
(inventory[i].flags2 & TR_ARTIFACT))
break; /* don't destroy artifacts -CFT */
objdes(t1, &inventory[i], FALSE);
/* stacked single items */
sprintf(t2, "%sour %s (%c) %s stolen!",
((inventory[i].subval <= ITEM_SINGLE_STACK_MAX) &&
(inventory[i].number > 1))
? "One of y" : "Y",
t1, i + 'a',
/* stacked group items */
((inventory[i].subval > ITEM_SINGLE_STACK_MAX) &&
(inventory[i].number > 1))
? "were" : "was");
msg_print(t2);
inven_destroy(i);
}
if (randint(3) == 1) {
msg_print("There is a puff of smoke!");
blinked = 1; /* added -CFT */
teleport_away(monptr, MAX_SIGHT);
}
break;
case 14: /* Poison */
f_ptr = &py.flags;
take_hit(damage, ddesc);
if (!(f_ptr->poison_im || f_ptr->poison_resist ||
f_ptr->resist_poison)) {
msg_print("You feel very sick.");
f_ptr->poisoned += randint((int)r_ptr->level) + 5;
} else {
msg_print("The poison has no effect.");
}
break;
case 15: /* Lose dexterity */
f_ptr = &py.flags;
take_hit(damage, ddesc);
if (f_ptr->sustain_dex)
msg_print("You feel clumsy for a moment, but it passes.");
else {
msg_print("You feel more clumsy.");
(void)dec_stat(A_DEX);
}
break;
case 16: /* Lose constitution */
f_ptr = &py.flags;
take_hit(damage, ddesc);
if (f_ptr->sustain_con)
msg_print("Your body resists the effects of the disease.");
else {
msg_print("Your health is damaged!");
(void)dec_stat(A_CON);
}
break;
case 17: /* Lose intelligence */
f_ptr = &py.flags;
take_hit(damage, ddesc);
msg_print("You have trouble thinking clearly.");
if (f_ptr->sustain_int)
msg_print("But your mind quickly clears.");
else
(void)dec_stat(A_INT);
break;
case 18: /* Lose wisdom */
f_ptr = &py.flags;
take_hit(damage, ddesc);
if (f_ptr->sustain_wis)
msg_print("Your wisdom is sustained.");
else {
msg_print("Your wisdom is drained.");
(void)dec_stat(A_WIS);
}
break;
case 19: /* Lose experience */
f_ptr = &py.flags;
if (f_ptr->hold_life && randint(5) > 1)
msg_print("You keep hold of your life force!");
else {
if (f_ptr->hold_life) {
msg_print("You feel your life slipping away!");
lose_exp(damage + (py.misc.exp/1000) * MON_DRAIN_LIFE);
} else {
msg_print("You feel your life draining away!");
lose_exp(damage + (py.misc.exp/100) * MON_DRAIN_LIFE);
}
}
break;
case 20: /* Aggravate monster */
(void)aggravate_monster(20);
break;
case 21: /* Disenchant */
if (!py.flags.disenchant_resist) {
int8u chance = 0;
take_hit(damage, ddesc);
flag = FALSE;
switch (randint(7)) {
case 1:
i = INVEN_WIELD;
break;
case 2:
i = INVEN_BODY;
break;
case 3:
i = INVEN_ARM;
break;
case 4:
i = INVEN_OUTER;
break;
case 5:
i = INVEN_HANDS;
break;
case 6:
i = INVEN_HEAD;
break;
case 7:
i = INVEN_FEET;
break;
}
i_ptr = &inventory[i];
if (i_ptr->tval != TV_NOTHING) {
if (i_ptr->flags2 & TR_ARTIFACT)
chance = randint(5);
if ((i_ptr->tohit > 0) && (chance < 3)){
i_ptr->tohit -= randint(2);
/* don't send it below zero */
if (i_ptr->tohit < 0)
i_ptr->tohit = 0;
flag = TRUE;
}
if ((i_ptr->todam > 0) && (chance < 3)) {
i_ptr->todam -= randint(2);
/* don't send it below zero */
if (i_ptr->todam < 0)
i_ptr->todam = 0;
flag = TRUE;
}
if ((i_ptr->toac > 0) && (chance < 3)) {
i_ptr->toac -= randint(2);
/* don't send it below zero */
if (i_ptr->toac < 0)
i_ptr->toac = 0;
flag = TRUE;
}
if (flag || (chance > 2)) {
vtype t1, t2;
objdes(t1, &inventory[i], FALSE);
if (chance < 3)
sprintf(t2, "Your %s (%c) %s disenchanted!", t1,
i+'a'-INVEN_WIELD,
(inventory[i].number != 1) ? "were":"was");
else
sprintf(t2, "Your %s (%c) %s disenchantment!", t1,
i+'a'-INVEN_WIELD,
(inventory[i].number != 1) ? "resist":"resists");
msg_print (t2);
calc_bonuses ();
}
else
notice = FALSE;
}
}
break;
case 22: /* Eat food */
if (find_range(TV_FOOD, TV_NEVER, &i, &j)) {
inven_destroy(i);
msg_print("It got at your rations!");
} else
notice = FALSE;
break;
case 23: /* Eat light */
i_ptr = &inventory[INVEN_LIGHT];
if ((i_ptr->p1 > 0) && ((i_ptr->flags2 & TR_ARTIFACT) == 0)) {
i_ptr->p1 -= (250 + randint(250));
if (i_ptr->p1 < 1)
i_ptr->p1 = 1;
if (py.flags.blind < 1)
msg_print("Your light dims.");
else
notice = FALSE;
} else
notice = FALSE;
break;
case 24: /* Eat charges */
i = randint(inven_ctr) - 1;
j = r_ptr->level;
i_ptr = &inventory[i];
if (((i_ptr->tval == TV_STAFF) || (i_ptr->tval == TV_WAND))
&& (i_ptr->p1 > 0)) {
m_ptr->hp += j * i_ptr->p1;
i_ptr->p1 = 0;
if (!known2_p(i_ptr))
add_inscribe(i_ptr, ID_EMPTY);
msg_print("Energy drains from your pack!");
} else
notice = FALSE;
break;
case 25: /* Drain all stats. Haha! SM */
f_ptr = &py.flags;
take_hit(damage, ddesc);
if (py.flags.sustain_str)
msg_print("You feel weaker for a moment, but it passes.");
else {
msg_print("You feel weaker.");
(void)dec_stat(A_STR);
}
if (f_ptr->sustain_dex)
msg_print("You feel clumsy for a moment, but it passes.");
else {
msg_print("You feel more clumsy.");
(void)dec_stat(A_DEX);
}
if (f_ptr->sustain_con)
msg_print("Your body resists the effects of the disease.");
else {
msg_print("Your health is damaged!");
(void)dec_stat(A_CON);
}
msg_print("You have trouble thinking clearly.");
if (f_ptr->sustain_int)
msg_print("But your mind quickly clears.");
else
(void)dec_stat(A_INT);
if (f_ptr->sustain_wis)
msg_print("Your wisdom is sustained.");
else {
msg_print("Your wisdom is drained.");
(void)dec_stat(A_WIS);
}
if (f_ptr->sustain_chr)
msg_print("You keep your good looks.");
else {
msg_print("Your features are twisted.");
(void)dec_stat(A_CHR);
}
break;
case 99:
notice = FALSE;
break;
default:
notice = FALSE;
break;
}
if (CUT && STUN) {
switch (randint(2)) {
case 1:
CUT = FALSE;
break;
case 2:
STUN = FALSE;
break;
}
}
switch (monster_critical(adice, asides, damage)) {
case 0:
break;
case 1:
if (CUT)
cut_player(randint(5));
else if (STUN)
stun_player(randint(5));
break;
case 2:
if (CUT)
cut_player(randint(5) + 5);
else if (STUN)
stun_player(randint(5) + 5);
break;
case 3:
if (CUT)
cut_player(randint(30) + 20);
else if (STUN)
stun_player(randint(20) + 10);
break;
case 4:
if (CUT)
cut_player(randint(70) + 30);
else if (STUN)
stun_player(randint(40) + 30);
break;
case 5:
if (CUT)
cut_player(randint(250) + 50);
else if (STUN)
stun_player(randint(50) + 40);
break;
case 6:
if (CUT)
cut_player(300);
else if (STUN)
stun_player(randint(60) + 57);
break;
default:
if (CUT)
cut_player(5000);
else if (STUN)
stun_player(100 + randint(10));
break;
}
/* moved here from mon_move, so that monster only confused if it actually hits */
if (!attype) { /* if no attacks, monster can't get confused -dbd */
if (py.flags.confuse_monster && py.flags.protevil <= 0) {
msg_print("Your hands stop glowing.");
py.flags.confuse_monster = FALSE;
if ((randint(MAX_MONS_LEVEL) < r_ptr->level) ||
(CHARM_SLEEP & r_ptr->cdefense))
(void)sprintf(tmp_str, "%sis unaffected.", cdesc);
else {
(void)sprintf(tmp_str, "%sappears confused.", cdesc);
m_ptr->confused = TRUE;
}
msg_print(tmp_str);
if (visible && !death && randint(4) == 1)
c_recall[m_ptr->mptr].r_cdefense |= r_ptr->cdefense &
CHARM_SLEEP;
}
}
/*
* increase number of attacks if notice true, or if had previously
* noticed the attack (in which case all this does is help player
* learn damage), note that in the second case do not increase
* attacks if creature repelled (no damage done)
*/
if ((notice ||
(c_recall[m_ptr->mptr].r_attacks[attackn] != 0 &&
attype != 99))
&& c_recall[m_ptr->mptr].r_attacks[attackn] < MAX_UCHAR)
c_recall[m_ptr->mptr].r_attacks[attackn]++;
if (visible && death && c_recall[m_ptr->mptr].r_deaths < MAX_SHORT)
c_recall[m_ptr->mptr].r_deaths++;
} else {
if ((adesc >= 1 && adesc <= 3) || (adesc == 6)) {
disturb(1, 0);
(void)strcpy(tmp_str, cdesc);
msg_print(strcat(tmp_str, "misses you."));
}
}
if (attackn < MAX_MON_NATTACK - 1)
attackn++;
else
break;
}
}
/* Make the move if possible, five choices -RAK- */
static void
make_move(monptr, mm, rcmove)
int monptr, *mm;
int32u *rcmove;
{
int i, newy, newx, do_turn, do_move, stuck_door;
int32u movebits;
register cave_type *c_ptr;
register monster_type *m_ptr;
register inven_type *t_ptr;
#ifdef ATARIST_MWC
int32u holder;
#endif
i = 0;
do_turn = FALSE;
do_move = FALSE;
m_ptr = &m_list[monptr];
movebits = c_list[m_ptr->mptr].cmove;
do {
/* Get new position */
newy = m_ptr->fy;
newx = m_ptr->fx;
(void)mmove(mm[i], &newy, &newx);
c_ptr = &cave[newy][newx];
if ((i == 4) && (m_ptr->monfear) && /* cornered (or things in the way!) -CWS */
((c_ptr->fval > MAX_OPEN_SPACE) || (c_ptr->cptr > 1))) {
creature_type *r_ptr = &c_list[m_ptr->mptr];
vtype m_name, out_val;
m_ptr->monfear = 0;
if (m_ptr->ml && los(char_row, char_col, m_ptr->fy, m_ptr->fx)) {
monster_name(m_name, m_ptr, r_ptr);
sprintf(out_val, "%s turns to fight!", m_name);
msg_print(out_val);
}
break; /* don't try to actually do anything -CWS */
}
if (c_ptr->fval != BOUNDARY_WALL) {
/* Floor is open? */
if (c_ptr->fval <= MAX_OPEN_SPACE)
do_move = TRUE;
/* Creature moves through walls? */
else if (movebits & CM_PHASE) {
do_move = TRUE;
*rcmove |= CM_PHASE;
} else if (c_list[m_ptr->mptr].cdefense & BREAK_WALL) {
/* Crunch up those Walls Morgoth and Umber Hulks!!!! */
t_ptr = &t_list[c_ptr->tptr];
do_move = TRUE;
c_recall[m_ptr->mptr].r_cdefense |= BREAK_WALL;
if ((t_ptr->tval == TV_CLOSED_DOOR) ||
(t_ptr->tval == TV_SECRET_DOOR)) { /* break the door -CFT */
invcopy(t_ptr, OBJ_OPEN_DOOR);
t_ptr->p1 = (-1); /* make it broken, not just open */
c_ptr->fval = CORR_FLOOR; /* change floor setting */
lite_spot(newy, newx); /* show broken door */
msg_print("You hear a door burst open!");
disturb(1, 0);
} else /* otherwise, break those walls! -CFT */
(void)twall(newy, newx, 1, 0);
}
/* Creature can open doors? */
else if (c_ptr->tptr != 0) {
t_ptr = &t_list[c_ptr->tptr];
if (movebits & CM_OPEN_DOOR) { /* Creature can open doors. */
stuck_door = FALSE;
if (t_ptr->tval == TV_CLOSED_DOOR) {
do_turn = TRUE;
if ((m_ptr->monfear) && randint(2) == 1) /* afraid */
t_ptr->p1 = 0;
if (t_ptr->p1 == 0) /* Closed door */
do_move = TRUE;
else if (t_ptr->p1 > 0) { /* Locked doors */
if (randint((m_ptr->hp + 1) * (50 + t_ptr->p1)) <
40 * (m_ptr->hp - 10 - t_ptr->p1))
t_ptr->p1 = 0;
} else if (t_ptr->p1 < 0) { /* Stuck doors */
if (randint((m_ptr->hp + 1) * (50 - t_ptr->p1)) <
40 * (m_ptr->hp - 10 + t_ptr->p1)) {
msg_print("You hear a door burst open!");
disturb(1, 0);
stuck_door = TRUE;
do_move = TRUE;
}
}
} else if (t_ptr->tval == TV_SECRET_DOOR) {
do_turn = TRUE;
do_move = TRUE;
}
if (do_move) {
invcopy(t_ptr, OBJ_OPEN_DOOR);
if (stuck_door) /* 50% chance of breaking door */
t_ptr->p1 = 1 - randint(2);
c_ptr->fval = CORR_FLOOR;
lite_spot(newy, newx);
*rcmove |= CM_OPEN_DOOR;
do_move = FALSE;
}
} else { /* Creature can not open doors, must bash them */
if (t_ptr->tval == TV_CLOSED_DOOR) {
do_turn = TRUE;
if (randint((m_ptr->hp + 1) * (80 + MY_ABS(t_ptr->p1))) <
40 * (m_ptr->hp - 20 - MY_ABS(t_ptr->p1))) {
invcopy(t_ptr, OBJ_OPEN_DOOR);
/* 50% chance of breaking door */
t_ptr->p1 = 1 - randint(2);
c_ptr->fval = CORR_FLOOR;
lite_spot(newy, newx);
msg_print("You hear a door burst open!");
disturb(1, 0);
}
}
}
}
/* Glyph of warding present? */
if (do_move && (c_ptr->tptr != 0) &&
(t_list[c_ptr->tptr].tval == TV_VIS_TRAP) &&
(t_list[c_ptr->tptr].subval == 99)) {
if (randint(OBJ_RUNE_PROT) < c_list[m_ptr->mptr].level) {
if ((newy == char_row) && (newx == char_col))
msg_print("The rune of protection is broken!");
(void)delete_object(newy, newx);
} else {
do_move = FALSE;
/* If the creature moves only to attack, don't let it move if the glyph
* prevents it from attacking */
if (movebits & CM_ATTACK_ONLY)
do_turn = TRUE;
}
}
/* Creature has attempted to move on player? */
if (do_move)
if (c_ptr->cptr == 1) {
/*
* if the monster is not lit, must call update_mon, it may be
* faster than character, and hence could have just moved
* next to character this same turn
*/
if (!m_ptr->ml)
update_mon(monptr);
make_attack(monptr);
do_move = FALSE;
do_turn = TRUE;
}
/* Creature is attempting to move on other creature? */
else if ((c_ptr->cptr > 1) &&
((newy != m_ptr->fy) ||
(newx != m_ptr->fx))) {
/* Creature eats other creatures? */
#ifdef ATARIST_MWC
if ((movebits & (holder = CM_EATS_OTHER)) &&
#else
if ((movebits & CM_EATS_OTHER) &&
#endif
(c_list[m_ptr->mptr].mexp >
c_list[m_list[c_ptr->cptr].mptr].mexp)) {
if (m_list[c_ptr->cptr].ml)
#ifdef ATARIST_MWC
*rcmove |= holder;
#else
*rcmove |= CM_EATS_OTHER;
#endif
/* It ate an already processed monster. Handle normally. */
if (monptr < c_ptr->cptr)
delete_monster((int)c_ptr->cptr);
/*
* If it eats this monster, an already processed monster
* will take its place, causing all kinds of havoc.
* Delay the kill a bit.
*/
else
fix1_delete_monster((int)c_ptr->cptr);
} else
do_move = FALSE;
}
/* Creature has been allowed move. */
if (do_move) {
/* Move creature record */
move_rec((int)m_ptr->fy, (int)m_ptr->fx, newy, newx);
if (m_ptr->ml) {
m_ptr->ml = FALSE;
lite_spot((int)m_ptr->fy, (int)m_ptr->fx);
}
m_ptr->fy = newy;
m_ptr->fx = newx;
m_ptr->cdis = distance(char_row, char_col, newy, newx);
do_turn = TRUE;
/* Pick up or eat an object */
#ifdef ATARIST_MWC
if (movebits & (holder = CM_PICKS_UP))
#else
if (movebits & CM_PICKS_UP)
#endif
{
/* used in code to prevent orcs from picking up Slay Orc weapons, etc -CFT */
int32u t;
c_ptr = &cave[newy][newx];
if ((c_ptr->tptr != 0)
&& (t_list[c_ptr->tptr].tval <= TV_MAX_OBJECT)) {
#ifdef ATARIST_MWC
*rcmove |= holder;
#else
*rcmove |= CM_PICKS_UP;
#endif
t = 0L;
if ((t_list[c_ptr->tptr].flags & TR_SLAY_DRAGON) ||
(t_list[c_ptr->tptr].flags & TR_SLAY_X_DRAGON))
t |= DRAGON;
if (t_list[c_ptr->tptr].flags & TR_SLAY_UNDEAD)
t |= UNDEAD;
if (t_list[c_ptr->tptr].flags2 & TR_SLAY_DEMON)
t |= DEMON;
if (t_list[c_ptr->tptr].flags2 & TR_SLAY_TROLL)
t |= TROLL;
if (t_list[c_ptr->tptr].flags2 & TR_SLAY_GIANT)
t |= GIANT;
if (t_list[c_ptr->tptr].flags2 & TR_SLAY_ORC)
t |= ORC;
/* if artifact, or wearable & hurts this monster -CWS */
if ((t_list[c_ptr->tptr].flags2 & TR_ARTIFACT) ||
( (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
(t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
(c_list[m_ptr->mptr].cdefense & t) )) {
/* FIXME: should use new line-splitting code */
vtype m_name, out_val, i_name;
int ii, split = (-1);
update_mon(monptr); /* make sure ml see right -CFT */
if ((m_ptr->ml) && los(char_row, char_col, m_ptr->fy,
m_ptr->fx)) {
/* if we can see it, tell us what happened -CFT */
monster_name(m_name, m_ptr, &(c_list[m_ptr->mptr]));
objdes(i_name, &(t_list[c_ptr->tptr]), TRUE);
sprintf(out_val,
"%s tries to pick up %s, but stops suddenly!",
m_name, i_name);
for (ii = 0; ii < 72 && out_val[ii]; ii++)
if (out_val[ii] == ' ')
split = ii;
if ((ii > 71) && (split != (-1))) {
/* then we should probably split it -CFT */
out_val[split] = 0;
msg_print(out_val);
msg_print(&out_val[split + 1]);
} else
/* if ii <= 71, then it'll fit nicely in 1 line.
* Or, we found no space to split at... -CFT */
msg_print(out_val);
} /* if can see */
}
/* if shouldn't pick up */
else
(void)delete_object(newy, newx);
}
}
}
}
i++;
/* Up to 5 attempts at moving, give up. */
}
while ((!do_turn) && (i < 5));
}
/* Creatures can cast spells too. (Dragon Breath) -RAK- */
/* cast_spell = true if creature changes position */
/* took_turn = true if creature casts a spell */
static void
mon_cast_spell(monptr, took_turn)
int monptr, *took_turn;
{
int32u i;
int y, x, chance, thrown_spell, r1;
register int k;
int spell_choice[64], desperate = FALSE;
vtype cdesc, outval, ddesc;
register struct flags *f_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
char sex;
int blind = (py.flags.blind > 0);
/* alter msgs if player can't see -CFT */
if (death)
return;
m_ptr = &m_list[monptr];
r_ptr = &c_list[m_ptr->mptr];
sex = r_ptr->gender;
/* 1 in x chance of casting spell */
chance = (int)(r_ptr->spells & CS_FREQ);
if (chance == 0) {
msg_print("CHANCE == 0");
msg_print("caused by ....");
msg_print(r_ptr->name);
*took_turn = FALSE;
} else if (randint(chance) != 1)
*took_turn = FALSE;
/* Must be within certain range */
else if (m_ptr->cdis > MAX_SPELL_DIS)
*took_turn = FALSE;
/* Must have unobstructed Line-Of-Sight (reversed direction -CWS) */
else if (!los((int)m_ptr->fy, (int)m_ptr->fx, char_row, char_col))
*took_turn = FALSE;
else { /* Creature is going to cast a spell */
*took_turn = TRUE;
/* Check to see if monster should be lit. */
update_mon(monptr);
/* Describe the attack */
if (m_ptr->ml) {
if (r_ptr->cdefense & UNIQUE)
(void)sprintf(cdesc, "%s ", r_ptr->name);
else
(void)sprintf(cdesc, "The %s ", r_ptr->name);
} else
(void)strcpy(cdesc, "It ");
/* For "DIED_FROM" string */
if (UNIQUE & r_ptr->cdefense)
(void)sprintf(ddesc, "%s", r_ptr->name);
else if (is_a_vowel(r_ptr->name[0]))
(void)sprintf(ddesc, "an %s", r_ptr->name);
else
(void)sprintf(ddesc, "a %s", r_ptr->name);
/* End DIED_FROM */
/* Extract all possible spells into spell_choice */
if ((r_ptr->cdefense & INTELLIGENT) &&
(m_ptr->hp < ((r_ptr->hd[0] * r_ptr->hd[1]) / 10)) &&
(r_ptr->spells & CS_INT1 || r_ptr->spells2 & CS_INT2 ||
r_ptr->spells3 & CS_INT3) && randint(2) == 1) {
desperate = TRUE;
c_recall[m_ptr->mptr].r_cdefense |= INTELLIGENT;
}
i = (r_ptr->spells & ~CS_FREQ);
if (desperate)
i &= CS_INT1;
k = 0;
while (i != 0) {
spell_choice[k] = bit_pos(&i);
k++;
}
i = r_ptr->spells2;
if (desperate)
i &= CS_INT2;
while (i != 0) {
spell_choice[k] = bit_pos(&i) + 32;
k++;
}
i = r_ptr->spells3;
if (desperate)
i &= CS_INT3;
while (i != 0) {
spell_choice[k] = bit_pos(&i) + 64;
k++;
}
/* Choose a spell to cast */
if (!k)
thrown_spell = 200;
else
thrown_spell = spell_choice[randint(k) - 1];
thrown_spell++;
/* all except teleport_away() and drain mana spells always disturb */
if (thrown_spell > 6 && thrown_spell != 7)
disturb(1, 0);
/* Cast the spell. */
switch (thrown_spell) {
case 5: /* Teleport Short */
(void)strcat(cdesc, "blinks away.");
msg_print(cdesc);
teleport_away(monptr, 5);
break;
case 6: /* Teleport Long */
(void)strcat(cdesc, "teleports away.");
msg_print(cdesc);
teleport_away(monptr, MAX_SIGHT);
break;
case 7: /* Teleport To */
(void)strcat(cdesc, "commands you to return!");
msg_print(cdesc);
teleport_to((int)m_ptr->fy, (int)m_ptr->fx);
break;
case 8: /* Light Wound */
if (!blind)
(void)strcat(cdesc, "points at you and curses.");
else
(void)strcat(cdesc, "mumbles.");
msg_print(cdesc);
if (player_saves())
msg_print("You resist the effects of the spell.");
else
take_hit(damroll(3, 8), ddesc);
break;
case 9: /* Serious Wound */
if (!blind)
(void)strcat(cdesc, "points at you and curses horribly.");
else
(void)strcat(cdesc, "mumbles.");
msg_print(cdesc);
if (player_saves())
msg_print("You resist the effects of the spell.");
else
take_hit(damroll(8, 8), ddesc);
break;
case 10: /* Hold Person */
if (!blind)
(void)strcat(cdesc, "gazes deep into your eyes!");
else
(void)strcat(cdesc,
"mumbles, and you feel something holding you!");
msg_print(cdesc);
if (py.flags.free_act)
msg_print("You are unaffected.");
else if (player_saves())
if (!blind)
msg_print("You stare back unafraid!");
else
msg_print("You resist!");
else if (py.flags.paralysis > 0)
py.flags.paralysis += 2;
else
py.flags.paralysis = randint(5) + 4;
break;
case 11: /* Cause Blindness */
if (!blind)
(void)strcat(cdesc, "casts a spell, burning your eyes!");
else
(void)strcat(cdesc, "mumbles, and your eyes burn even more.");
msg_print(cdesc);
if ((player_saves()) || (py.flags.blindness_resist))
if (!blind)
msg_print("You blink and your vision clears.");
else
msg_print("But the extra burning quickly fades away.");
else if (py.flags.blind > 0)
py.flags.blind += 6;
else
py.flags.blind += 12 + randint(3);
break;
case 12: /* Cause Confuse */
if (!blind)
(void)strcat(cdesc, "creates a mesmerising illusion.");
else
(void)strcat(cdesc, "mumbles, and you hear puzzling noises.");
msg_print(cdesc);
if ((player_saves()) || (py.flags.confusion_resist)
|| (py.flags.chaos_resist))
msg_print("You disbelieve the feeble spell.");
else if (py.flags.confused > 0)
py.flags.confused += 2;
else
py.flags.confused = randint(5) + 3;
break;
case 13: /* Cause Fear */
if (!blind)
(void)strcat(cdesc, "casts a fearful illusion.");
else
(void)strcat(cdesc, "mumbles, and you hear scary noises.");
msg_print(cdesc);
if (player_saves() || py.flags.fear_resist)
msg_print("You refuse to be frightened.");
else if (py.flags.afraid > 0)
py.flags.afraid += 2;
else
py.flags.afraid = randint(5) + 3;
break;
case 14: /* Summon Monster */
if (!blind)
(void)strcat(cdesc, "magically summons help!");
else
(void)strcat(cdesc,
"mumbles, and you hear something appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called,it needs monptr */
hack_monptr = monptr;
(void)summon_monster(&y, &x, FALSE);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
break;
case 15: /* Summon Undead */
if (!blind)
(void)strcat(cdesc,
"magically summons help from beyond the grave!");
else
(void)strcat(cdesc,
"mumbles, and you hear something creepy appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called,it needs monptr */
hack_monptr = monptr;
(void)summon_undead(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
break;
case 16: /* Slow Person */
(void)strcat(cdesc, "drains power from your muscles!");
msg_print(cdesc);
if (py.flags.free_act)
msg_print("You are unaffected.");
else if (player_saves())
msg_print("Your body resists the spell.");
else if (py.flags.slow > 0)
py.flags.slow += 2;
else
py.flags.slow = randint(5) + 3;
break;
case 17: /* Drain Mana */
if (py.misc.cmana > 0) {
disturb(1, 0);
(void)sprintf(outval,
"%sdraws psychic energy from you!", cdesc);
msg_print(outval);
if (m_ptr->ml) {
(void)sprintf(outval, "%sappears healthier.", cdesc);
msg_print(outval);
}
r1 = (randint((int)r_ptr->level) >> 1) + 1;
if (r1 > py.misc.cmana) {
r1 = py.misc.cmana;
py.misc.cmana = 0;
py.misc.cmana_frac = 0;
} else
py.misc.cmana -= r1;
prt_cmana();
m_ptr->hp += 6 * (r1);
}
break;
case 18: /* Summon Demon */
if (!blind)
(void)strcat(cdesc, "summons a hellish adversary!");
else
(void)strcat(cdesc,
"mumbles, and you smell fire and brimstone nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called,it needs monptr */
hack_monptr = monptr;
(void)summon_demon(c_list[m_ptr->mptr].level, &y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
break;
case 19: /* Summon Dragon */
if (!blind)
(void)strcat(cdesc, "magically summons a Dragon!");
else
(void)strcat(cdesc,
"mumbles, and you hear something large appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called,it needs monptr */
hack_monptr = monptr;
(void)summon_dragon(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
break;
case 20: /* Breath Light */
if (!blind)
(void)strcat(cdesc, "breathes lightning.");
else
(void)strcat(cdesc, "breathes, and you get zapped.");
msg_print(cdesc);
breath(GF_LIGHTNING, char_row, char_col,
((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)),
ddesc, monptr);
break;
case 21: /* Breath Gas */
if (!blind)
(void)strcat(cdesc, "breathes gas.");
else
(void)strcat(cdesc, "breathes, and you inhale noxious gases.");
msg_print(cdesc);
breath(GF_POISON_GAS, char_row, char_col,
((m_ptr->hp / 3) > 800 ? 800 : (m_ptr->hp / 3)), ddesc, monptr);
break;
case 22: /* Breath Acid */
if (!blind)
(void)strcat(cdesc, "breathes acid.");
else
(void)strcat(cdesc, "breathes, and your skin is burning.");
msg_print(cdesc);
breath(GF_ACID, char_row, char_col,
((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)),
ddesc, monptr);
break;
case 23: /* Breath Frost */
if (!blind)
(void)strcat(cdesc, "breathes frost.");
else
(void)strcat(cdesc, "breathes, and feel a frigid blast.");
msg_print(cdesc);
breath(GF_FROST, char_row, char_col,
((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)),
ddesc, monptr);
break;
case 24: /* Breath Fire */
if (!blind)
(void)strcat(cdesc, "breathes fire.");
else
(void)strcat(cdesc, "breathes, and you're on fire.");
msg_print(cdesc);
breath(GF_FIRE, char_row, char_col,
((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)),
ddesc, monptr);
break;
case 25: /* Fire Bolt */
if (!blind)
(void)strcat(cdesc, "casts a Fire bolt.");
else
(void)strcat(cdesc, "mumbles.");
msg_print(cdesc);
bolt(GF_FIRE, char_row, char_col,
damroll(9, 8) + (c_list[m_ptr->mptr].level / 3)
,ddesc, m_ptr, monptr);
break;
case 26: /* Frost Bolt */
if (!blind)
(void)strcat(cdesc, "casts a Frost bolt.");
else
(void)strcat(cdesc, "mumbles, and you feel a frigid blast .");
msg_print(cdesc);
bolt(GF_FROST, char_row, char_col,
damroll(6, 8) + (c_list[m_ptr->mptr].level / 3)
,ddesc, m_ptr, monptr);
break;
case 27: /* Acid Bolt */
if (!blind)
(void)strcat(cdesc, "casts a Acid bolt.");
else
(void)strcat(cdesc, "mumbles, and your skin burns.");
msg_print(cdesc);
bolt(GF_ACID, char_row, char_col,
damroll(7, 8) + (c_list[m_ptr->mptr].level / 3)
,ddesc, m_ptr, monptr);
break;
case 28: /* Magic Missiles */
if (!blind)
(void)strcat(cdesc, "casts a Magic missile.");
else
(void)strcat(cdesc, "mumbles, and you feel an arrow hit you.");
msg_print(cdesc);
bolt(GF_MAGIC_MISSILE, char_row, char_col,
damroll(2, 6) + (c_list[m_ptr->mptr].level / 3)
,ddesc, m_ptr, monptr);
break;
case 29: /* Critical Wound */
if (!blind)
(void)strcat(cdesc, "points at you, incanting terribly!");
else
(void)strcat(cdesc, "mumbles loudly.");
msg_print(cdesc);
if (player_saves())
msg_print("You resist the effects of the spell.");
else
take_hit(damroll(10, 15), ddesc);
break;
case 30: /* Fire Ball */
if (!blind)
(void)strcat(cdesc, "casts a Fire ball.");
else
(void)strcat(cdesc, "mumbles, and you're on fire.");
msg_print(cdesc);
breath(GF_FIRE, char_row, char_col,
randint((c_list[m_ptr->mptr].level * 7) / 2) + 10,
ddesc, monptr);
break;
case 31: /* Frost Ball */
if (!blind)
(void)strcat(cdesc, "casts a Frost ball.");
else
(void)strcat(cdesc, "mumbles, and you feel a frigid blast.");
msg_print(cdesc);
breath(GF_FROST, char_row, char_col,
randint((c_list[m_ptr->mptr].level * 3) / 2) + 10,
ddesc, monptr);
break;
case 32: /* Mana Bolt */
if (!blind)
(void)strcat(cdesc, "casts a Mana bolt.");
else
(void)strcat(cdesc, "mumbles, and you feel a magical blast.");
msg_print(cdesc);
bolt(GF_MAGIC_MISSILE, char_row, char_col,
randint((c_list[m_ptr->mptr].level * 7) / 2) + 50, ddesc, m_ptr,
monptr);
break;
case 33:
if (!blind)
(void)strcat(cdesc, "breathes chaos.");
else
(void)strcat(cdesc, "breathes, and you feel a strange flux.");
msg_print(cdesc);
breath(GF_CHAOS, char_row, char_col,
((m_ptr->hp / 6) > 600 ? 600 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 34:
if (!blind)
(void)strcat(cdesc, "breathes shards.");
else
(void)strcat(cdesc, "breathes, and sharp fragments cut you.");
msg_print(cdesc);
breath(GF_SHARDS, char_row, char_col,
((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 35:
if (!blind)
(void)strcat(cdesc, "breathes sound.");
else
(void)strcat(cdesc, "breathes, and you are deafened.");
msg_print(cdesc);
breath(GF_SOUND, char_row, char_col,
((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 36:
if (!blind)
(void)strcat(cdesc, "breathes confusion.");
else
(void)strcat(cdesc, "breathes, and you feel dizzy.");
msg_print(cdesc);
breath(GF_CONFUSION, char_row, char_col,
((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 37:
if (!blind)
(void)strcat(cdesc, "breathes disenchantment.");
else
(void)strcat(cdesc,
"breathes, and your equipment seems less powerful.");
msg_print(cdesc);
breath(GF_DISENCHANT, char_row, char_col,
((m_ptr->hp / 6) > 500 ? 500 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 38:
if (!blind)
(void)strcat(cdesc, "breathes nether.");
else
(void)strcat(cdesc, "breathes, and you feel an unholy aura.");
msg_print(cdesc);
breath(GF_NETHER, char_row, char_col,
((m_ptr->hp / 6) > 550 ? 550 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 39:
if (!blind)
(void)strcat(cdesc, "casts a Lightning bolt.");
else
(void)strcat(cdesc, "mumbles.");
msg_print(cdesc);
bolt(GF_LIGHTNING, char_row, char_col,
damroll(4, 8) + (c_list[m_ptr->mptr].level / 3)
,ddesc, m_ptr, monptr);
break;
case 40:
if (!blind)
(void)strcat(cdesc, "casts a Lightning Ball.");
else
(void)strcat(cdesc, "mumbles, and you get zapped.");
msg_print(cdesc);
breath(GF_LIGHTNING, char_row, char_col,
randint((c_list[m_ptr->mptr].level * 3) / 2) + 8, ddesc, monptr);
break;
case 41:
if (!blind)
(void)strcat(cdesc, "casts an Acid Ball.");
else
(void)strcat(cdesc, "mumbles, and your skin is burning.");
msg_print(cdesc);
breath(GF_ACID, char_row, char_col,
randint(c_list[m_ptr->mptr].level * 3) + 15, ddesc, monptr);
break;
case 42:
if (!blind)
(void)strcat(cdesc, "casts a spell and cackles evilly.");
else
(void)strcat(cdesc, "mumbles, and then cackles evilly.");
msg_print(cdesc);
(void)trap_creation();
break;
case 43:
if (!blind)
(void)strcat(cdesc, "points at you, screaming the word DIE!");
else
(void)strcat(cdesc, "mumbles, and then screams 'DIE!'.");
msg_print(cdesc);
if (player_saves())
msg_print("You laugh at the feeble spell.");
else {
msg_print("You start to bleed!");
take_hit(damroll(15, 15), ddesc);
cut_player(m_ptr->hp);
}
break;
case 44:
if (!blind) {
(void)strcat(cdesc, "stares at you.");
msg_print(cdesc);
} else
msg_print("You feel something focusing on your mind.");
if (player_saves())
msg_print("You resist the effects.");
else {
msg_print("Your mind is blasted by psionic energy.");
if ((!py.flags.confusion_resist) && (!py.flags.chaos_resist)) {
if (py.flags.confused > 0)
py.flags.confused += 2;
else
py.flags.confused = randint(5) + 3;
}
take_hit(damroll(8, 8), ddesc);
}
break;
case 45:
(void)strcat(cdesc, "teleports you away.");
msg_print(cdesc);
(void)teleport(100);
break;
case 46: /* healing, added monster fear code -CWS */
if (!blind)
(void)sprintf(outval, "%sconcentrates on %s wounds.", cdesc,
(sex == 'm' ? "his" : sex == 'f' ? "her"
: sex == 'p' ? "their" : "its"));
else
(void)sprintf(outval, "%smumbles to itself.", cdesc);
msg_print(outval);
monster_is_afraid = 0;
if (m_ptr->maxhp == 0) { /* then we're just going to fix it!
* -CFT */
if ((c_list[m_ptr->mptr].cdefense & MAX_HP) || be_nasty)
m_ptr->maxhp = max_hp(c_list[m_ptr->mptr].hd);
else
m_ptr->maxhp = pdamroll(c_list[m_ptr->mptr].hd);
}
if (!blind) /* if we bother to say "mumbles" above, then shouldn't
* see it heal itself -CFT
*/
strcat(cdesc, "looks ");
else
strcat(cdesc, "sounds ");
if (m_ptr->hp >= m_ptr->maxhp) {
/* need >= because, if we recalc-ed maxhp, we might have gotten a low roll,
* which could be below hp -CFT
*/
(void)strcat(cdesc, "looks as healthy as can be.");
msg_print(cdesc);
if (m_ptr->monfear > 0) { /* can't be afraid at max hp's */
m_ptr->monfear = 0;
monster_is_afraid = (-1);
}
} else {
m_ptr->hp += (c_list[m_ptr->mptr].level) * 6;
if (m_ptr->hp > m_ptr->maxhp)
m_ptr->hp = m_ptr->maxhp;
if (m_ptr->hp == m_ptr->maxhp) {
(void)strcat(cdesc, "looks REALLY healthy!");
if (m_ptr->monfear > 0) { /* can't be afraid at max
* hp's */
m_ptr->monfear = 0;
monster_is_afraid = (-1);
}
} else {
(void)strcat(cdesc, "looks healthier.");
if ((m_ptr->monfear > 0) && (m_ptr->maxhp / (m_ptr->hp + 1) < 3)) {
m_ptr->monfear = 0; /* has recovered 33% of it's
* hit points */
monster_is_afraid = (-1);
}
}
msg_print(cdesc);
if (monster_is_afraid == -1) { /* no longer afraid -CWS */
vtype m_name, out_val;
monster_name(m_name, m_ptr, &c_list[m_ptr->mptr]);
sprintf(out_val, "%s recovers %s courage.", m_name,
(sex == 'm' ? "his" : sex == 'f' ? "her" :
sex == 'p' ? "their" : "its"));
msg_print(out_val);
}
}
break;
case 47:
if (!blind)
(void)sprintf(outval, "%scasts a spell.", cdesc);
else
(void)sprintf(outval, "%smumbles to %sself.", cdesc,
(sex == 'm' ? "him" : sex == 'f' ? "her" :
sex == 'p' ? "them" : "it"));
msg_print(outval);
if ((m_ptr->cspeed) <= ((int)(c_list[m_ptr->mptr].speed) - 10)) {
if ((c_list[m_ptr->mptr].speed) <= 15) {
(void)strcat(cdesc, "starts moving faster.");
msg_print(cdesc);
m_ptr->cspeed += 1;
}
}
break;
case 48:
if (!blind)
(void)strcat(cdesc, "fires missiles at you.");
else
(void)strcat(cdesc, "sounds like it threw something.");
msg_print(cdesc);
bolt(GF_ARROW, char_row, char_col,
damroll(6, 7), ddesc, m_ptr, monptr);
break;
case 49:
if (!blind)
(void)strcat(cdesc, "casts a Plasma Bolt.");
else
(void)strcat(cdesc,
"mumbles, and you are hit with a hellish blast.");
msg_print(cdesc);
bolt(GF_PLASMA, char_row, char_col,
10 + damroll(8, 7) + (c_list[m_ptr->mptr].level),
ddesc, m_ptr, monptr);
break;
case 50:
if (!blind)
(void)strcat(cdesc, "magically summons monsters!");
else
(void)strcat(cdesc,
"mumbles, and you hear many things appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called,it needs monptr */
for (k = 0; k < 8; k++) {
hack_monptr = monptr;
(void)summon_monster(&y, &x, FALSE);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
break;
case 51:
if (!blind)
(void)strcat(cdesc, "casts a Nether Bolt.");
else
(void)strcat(cdesc, "mumbles.");
msg_print(cdesc);
bolt(GF_NETHER, char_row, char_col,
30 + damroll(5, 5) + (c_list[m_ptr->mptr].level * 3) / 2,
ddesc, m_ptr, monptr);
break;
case 52:
if (!blind)
(void)strcat(cdesc, "casts an Ice Bolt.");
else
(void)strcat(cdesc, "mumbles.");
msg_print(cdesc);
bolt(GF_FROST, char_row, char_col,
damroll(6, 6) + (c_list[m_ptr->mptr].level)
,ddesc, m_ptr, monptr);
break;
case 53:
if (!blind)
(void)strcat(cdesc, "gestures in shadow.");
else
(void)strcat(cdesc, "mumbles.");
msg_print(cdesc);
(void)unlight_area(char_row, char_col);
break;
case 54:
(void)strcat(cdesc, "tries to blank your mind.");
msg_print(cdesc);
if (player_saves() || randint(2) == 1)
msg_print("You resist the spell.");
else if (lose_all_info())
msg_print("Your memories fade away.");
break;
case 55:
if (!blind) {
(void)sprintf(outval, "%sconcentrates and %s eyes glow red.",
cdesc,
(sex == 'm' ? "his" : sex == 'f' ? "her" :
sex == 'p' ? "their" : "its"));
msg_print(outval);
} else
msg_print("You feel something focusing on your mind.");
if (player_saves())
if (!blind)
msg_print("You avert your gaze!");
else
msg_print("You resist the effects.");
else {
msg_print("Your mind is blasted by psionic energy.");
take_hit(damroll(12, 15), ddesc);
if ((!py.flags.confusion_resist) && (!py.flags.chaos_resist)) {
if (py.flags.confused > 0)
py.flags.confused += 2;
else
py.flags.confused = randint(5) + 3;
}
if (!py.flags.free_act) {
if (py.flags.paralysis > 0)
py.flags.paralysis += 2;
else
py.flags.paralysis = randint(5) + 4;
if (py.flags.slow > 0)
py.flags.slow += 2;
else
py.flags.slow = randint(5) + 3;
}
if (!py.flags.blindness_resist) {
if (py.flags.blind > 0)
py.flags.blind += 6;
else
py.flags.blind += 12 + randint(3);
}
}
break;
case 56:
if (!blind)
(void)strcat(cdesc, "casts a Stinking Cloud.");
else
(void)strcat(cdesc, "mumbles, and you smell a foul odor.");
msg_print(cdesc);
breath(GF_POISON_GAS, char_row, char_col,
damroll(12, 2), ddesc, monptr);
break;
case 57:
if (!blind)
(void)strcat(cdesc, "gestures at you.");
else
(void)strcat(cdesc, "mumbles strangely.");
msg_print(cdesc);
if ((player_saves()) || (randint(3) != 1) ||
(py.flags.nexus_resist))
msg_print("You keep your feet firmly on the ground.");
else {
k = dun_level;
if (dun_level == Q_PLANE)
dun_level = 0;
else if (is_quest(dun_level))
dun_level -= 1;
else
dun_level += (-3) + 2 * randint(2);
if (dun_level < 0)
dun_level = 0;
if (k == Q_PLANE)
msg_print("You warp through a cross-dimension gate.");
else if (k < dun_level)
msg_print("You sink through the floor.");
else
msg_print("You rise up through the ceiling.");
new_level_flag = TRUE;
}
break;
case 58:
f_ptr = (&py.flags);
if (!blind)
(void)strcat(cdesc, "casts a Water Bolt.");
else
(void)strcat(cdesc, "mumbles.");
msg_print(cdesc);
bolt(GF_WATER, char_row, char_col,
damroll(10, 10) + (c_list[m_ptr->mptr].level)
,ddesc, m_ptr, monptr);
break;
case 59:
f_ptr = &py.flags;
if (!blind)
(void)strcat(cdesc, "gestures fluidly.");
else
(void)strcat(cdesc, "mumbles.");
msg_print(cdesc);
msg_print("You are engulfed in a whirlpool.");
breath(GF_WATER, char_row, char_col,
randint((c_list[m_ptr->mptr].level * 5) / 2) + 50,
ddesc, monptr);
break;
case 60:
if (!blind)
(void)strcat(cdesc, "casts a Nether Ball.");
else
(void)strcat(cdesc, "mumbles, and you feel an unholy aura.");
msg_print(cdesc);
breath(GF_NETHER, char_row, char_col,
(50 + damroll(10, 10) + (c_list[m_ptr->mptr].level)),
ddesc, monptr);
break;
case 61:
if (!blind)
(void)strcat(cdesc, "summons an Angel.");
else
(void)strcat(cdesc,
"mumbles, and you hear something appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called,it needs monptr */
hack_monptr = monptr;
(void)summon_angel(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
break;
case 62:
if (!blind)
(void)strcat(cdesc, "magically summons Spiders.");
else
(void)strcat(cdesc, "mumbles, and you hear many things appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called,it needs monptr */
for (k = 0; k < 6; k++) {
hack_monptr = monptr;
(void)summon_spider(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
break;
case 63:
if (!blind)
(void)strcat(cdesc, "magically summons Hounds.");
else
(void)strcat(cdesc, "mumbles, and you hear many things appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called,it needs monptr */
for (k = 0; k < 8; k++) {
hack_monptr = monptr;
(void)summon_hound(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
break;
case 64:
if (!blind)
(void)strcat(cdesc, "breathes Nexus.");
else
(void)strcat(cdesc, "breathes, and you feel strange.");
msg_print(cdesc);
breath(GF_NEXUS, char_row, char_col,
((m_ptr->hp / 3) > 250 ? 250 : (m_ptr->hp / 3)), ddesc, monptr);
break;
case 65:
if (!blind)
(void)strcat(cdesc, "breathes elemental force.");
else
(void)strcat(cdesc, "breathes, and you are hit hard.");
msg_print(cdesc);
if (randint(10) == 1)
br_wall(m_ptr->fy, m_ptr->fx);
else
breath(GF_FORCE, char_row, char_col,
((m_ptr->hp / 6) > 200 ? 200 : (m_ptr->hp / 6)),
ddesc, monptr);
break;
case 66:
if (!blind)
(void)strcat(cdesc, "breathes inertia.");
else
(void)strcat(cdesc, "breathes.");
msg_print(cdesc);
breath(GF_INERTIA, char_row, char_col,
((m_ptr->hp / 6) > 200 ? 200 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 67:
if (!blind)
(void)strcat(cdesc, "breathes light.");
else
(void)strcat(cdesc, "breathes.");
msg_print(cdesc);
breath(GF_LIGHT, char_row, char_col,
((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 68:
if (!blind)
(void)strcat(cdesc, "breathes time.");
else
(void)strcat(cdesc, "breathes.");
msg_print(cdesc);
breath(GF_TIME, char_row, char_col,
((m_ptr->hp / 3) > 150 ? 150 : (m_ptr->hp / 3)), ddesc, monptr);
break;
case 69: /* gravity */
if (!blind)
(void)strcat(cdesc, "breathes gravity.");
else
(void)strcat(cdesc, "breathes, and you feel heavy.");
msg_print(cdesc);
breath(GF_GRAVITY, char_row, char_col,
((m_ptr->hp / 3) > 200 ? 200 : (m_ptr->hp / 3)), ddesc, monptr);
break;
case 70: /* darkness */
if (!blind)
(void)strcat(cdesc, "breathes darkness.");
else
(void)strcat(cdesc, "breathes.");
msg_print(cdesc);
breath(GF_DARK, char_row, char_col,
((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 71: /* plasma */
if (!blind)
(void)strcat(cdesc, "breathes plasma.");
else
(void)strcat(cdesc, "breathes.");
msg_print(cdesc);
breath(GF_PLASMA, char_row, char_col,
((m_ptr->hp / 6) > 150 ? 150 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 72:
if (!blind) {
(void)strcat(cdesc, "fires an arrow at you.");
msg_print(cdesc);
} else
msg_print("You hear the 'twang' of a bowstring.");
bolt(GF_ARROW, char_row, char_col,
damroll(1, 6), ddesc, m_ptr, monptr);
break;
case 73:
if (!blind)
(void)strcat(cdesc, "magically summons mighty undead opponents.");
else
(void)strcat(cdesc, "mumbles, and you hear many creepy things appear.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called, it needs monptr */
for (k = 0; k < 10; k++) {
hack_monptr = monptr;
(void)summon_wraith(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
for (k = 0; k < 7; k++) {
hack_monptr = monptr;
(void)summon_gundead(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
break;
case 74: /* Big darkness storm */
if (!blind)
(void)strcat(cdesc, "casts a Darkness Storm.");
else
(void)strcat(cdesc, "mumbles powerfully.");
msg_print(cdesc);
breath(GF_DARK, char_row, char_col,
((m_ptr->hp / 6) > 500 ? 500 : (m_ptr->hp / 6)), ddesc, monptr);
break;
case 75: /* Mana storm */
if (!blind)
(void)strcat(cdesc, "invokes a Mana Storm.");
else
(void)strcat(cdesc, "mumbles, and you are hit by a storm of power.");
msg_print(cdesc);
breath(GF_MANA, char_row, char_col,
(c_list[m_ptr->mptr].level * 5) + damroll(10, 10),
ddesc, monptr);
break;
case 76: /* Summon reptiles */
if (!blind)
(void)strcat(cdesc, "magically summons reptiles.");
else
(void)strcat(cdesc, "mumbles, and you hear many things appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called, it needs monptr */
for (k = 0; k < 8; k++) {
hack_monptr = monptr;
(void)summon_reptile(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
break;
case 77: /* Summon ants */
if (!blind)
(void)strcat(cdesc, "magically summons ants.");
else
(void)strcat(cdesc, "mumbles, and you hear many things appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called, it needs monptr */
for (k = 0; k < 7; k++) {
hack_monptr = monptr;
(void)summon_ant(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
break;
case 78: /* Summon unique monsters */
if (!blind)
(void)strcat(cdesc, "summons special opponents!");
else
(void)strcat(cdesc,
"mumbles, and you're worried by the things you hear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called, it needs monptr */
for (k = 0; k < 5; k++) {
hack_monptr = monptr;
(void)summon_unique(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
for (k = 0; k < 4; k++) {
hack_monptr = monptr;
(void)summon_jabberwock(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
break;
case 79: /* Summon greater undead */
if (!blind)
(void)strcat(cdesc, "summons the DEAD!");
else
(void)strcat(cdesc, "mumbles, and a chill runs down your spine.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called, it needs monptr */
for (k = 0; k < 8; k++) {
hack_monptr = monptr;
(void)summon_gundead(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
break;
case 80: /* Summon ancient dragons */
if (!blind)
(void)strcat(cdesc, "summons ancient dragons.");
else
(void)strcat(cdesc, "mumbles, and you hear many huge things appear nearby.");
msg_print(cdesc);
y = char_row;
x = char_col;
/* in case compact_monster() is called, it needs monptr */
for (k = 0; k < 5; k++) {
hack_monptr = monptr;
(void)summon_ancientd(&y, &x);
hack_monptr = (-1);
update_mon((int)cave[y][x].cptr);
}
break;
default:
if (k != 200)
(void)strcat(cdesc, "casts a bugged spell.");
else
(void)strcat(cdesc, "had no spell to cast, tell someone NOW!");
msg_print(cdesc);
}
/* End of spells */
if ((m_ptr->ml) /* this won't work if we've been moved, so... */
||(thrown_spell == 45) /* add teleport away, */
||(thrown_spell == 57) /* and teleport lv -CFT */
) {
if (thrown_spell < 33)
c_recall[m_ptr->mptr].r_spells |= 1L << (thrown_spell - 1);
else if (thrown_spell < 65)
c_recall[m_ptr->mptr].r_spells2 |= 1L << (thrown_spell - 33);
else if (thrown_spell < 97) /* in case of 200 for bugs... -CFT */
c_recall[m_ptr->mptr].r_spells3 |= 1L << (thrown_spell - 65);
if ((c_recall[m_ptr->mptr].r_spells & CS_FREQ) != CS_FREQ)
c_recall[m_ptr->mptr].r_spells++;
if (death && c_recall[m_ptr->mptr].r_deaths < MAX_SHORT)
c_recall[m_ptr->mptr].r_deaths++;
}
}
}
/* Places creature adjacent to given location -RAK- */
/* Rats and Flys are fun! */
int
multiply_monster(y, x, cr_index, monptr)
int y, x, cr_index, monptr;
{
register int i, j, k;
register cave_type *c_ptr;
int result;
#ifdef ATARIST_MWC
int32u holder;
#endif
i = 0;
do {
j = y - 2 + randint(3);
k = x - 2 + randint(3);
/*
* don't create a new creature on top of the old one, that causes
* invincible/invisible creatures to appear
*/
if (in_bounds(j, k) && (j != y || k != x)) {
c_ptr = &cave[j][k];
if ((c_ptr->fval <= MAX_OPEN_SPACE) && (c_ptr->tptr == 0) &&
(c_ptr->cptr != 1)) {
if (c_ptr->cptr > 1) { /* Creature there already? */
/* Some critters are cannibalistic! */
if ((c_list[cr_index].cmove & CM_EATS_OTHER)
/* Check the experience level -CJS- */
&& c_list[cr_index].mexp >=
c_list[m_list[c_ptr->cptr].mptr].mexp) {
/* It ate an already processed monster.Handle normally. */
if (monptr < c_ptr->cptr)
delete_monster((int)c_ptr->cptr);
/*
* If it eats this monster, an already processed mosnter
* will take its place, causing all kinds of havoc. Delay
* the kill a bit.
*/
else
fix1_delete_monster((int)c_ptr->cptr);
/* in case compact_monster() is called,it needs monptr */
hack_monptr = monptr;
result = place_monster(j, k, cr_index, FALSE);
hack_monptr = (-1);
if (!result)
return FALSE;
mon_tot_mult++;
return check_mon_lite(j, k);
}
} else
/* All clear, place a monster */
{
/* in case compact_monster() is called,it needs monptr */
hack_monptr = monptr;
result = place_monster(j, k, cr_index, FALSE);
hack_monptr = (-1);
if (!result)
return FALSE;
mon_tot_mult++;
return check_mon_lite(j, k);
}
}
}
i++;
}
while (i <= 18);
return FALSE;
}
/* Move the critters about the dungeon -RAK- */
static void
mon_move(monptr, rcmove)
int monptr;
int32u *rcmove;
{
register int i, j;
int k, move_test, dir;
register creature_type *r_ptr;
register monster_type *m_ptr;
int mm[9];
bigvtype out_val, m_name;
m_ptr = &m_list[monptr];
r_ptr = &c_list[m_ptr->mptr];
/* reduce fear, tough monsters can unfear faster -CFT, hacked by DGK */
if (m_ptr->monfear) {
int t = (int)m_ptr->monfear; /* use int so avoid unsigned wraparound -CFT */
t -= randint(c_list[m_ptr->mptr].level / 10);
if (t <= 0) {
t = 0;
if (m_ptr->ml && los(char_row, char_col, m_ptr->fy, m_ptr->fx)) {
monster_name(m_name, m_ptr, r_ptr);
sprintf(out_val, "%s recovers its courage.", m_name);
msg_print(out_val);
}
}
m_ptr->monfear = (int8u) t;
}
/* Does the critter multiply? */
if ((r_ptr->cmove & CM_MULTIPLY) && (MAX_MON_MULT >= mon_tot_mult) &&
(((py.flags.rest != -1) && ((py.flags.rest % MON_MULT_ADJ) == 0)) ||
((py.flags.rest == -1) && (randint(MON_MULT_ADJ) == 1)))) {
k = 0;
for (i = (int)m_ptr->fy - 1; i <= (int)m_ptr->fy + 1; i++)
for (j = (int)m_ptr->fx - 1; j <= (int)m_ptr->fx + 1; j++)
if (in_bounds(i, j) && (cave[i][j].cptr > 1))
k++;
/* can't call randint with a value of zero, increment counter to allow
* creature multiplication
*/
if (k == 0)
k++;
if ((k < 4) && (randint(k * MON_MULT_ADJ) == 1))
if (multiply_monster((int)m_ptr->fy, (int)m_ptr->fx,
(int)m_ptr->mptr, monptr))
*rcmove |= CM_MULTIPLY;
}
move_test = FALSE;
/* if in wall, must immediately escape to a clear area */
if (!(r_ptr->cmove & CM_PHASE) &&
(cave[m_ptr->fy][m_ptr->fx].fval >= MIN_CAVE_WALL)) {
/* If the monster is already dead, don't kill it again! This can happen
* for monsters moving faster than the player. They will get multiple
* moves, but should not if they die on the first move. This is only a
* problem for monsters stuck in rock.
*/
if (m_ptr->hp < 0)
return;
k = 0;
dir = 1;
/* note direction of for loops matches direction of keypad from 1 to 9 */
/* do not allow attack against the player */
for (i = m_ptr->fy + 1; i >= (int)(m_ptr->fy - 1); i--)
for (j = m_ptr->fx - 1; j <= (int)(m_ptr->fx + 1); j++) {
if ((dir != 5) && (cave[i][j].fval <= MAX_OPEN_SPACE)
&& (cave[i][j].cptr != 1))
mm[k++] = dir;
dir++;
}
if (k != 0) {
/* put a random direction first */
dir = randint(k) - 1;
i = mm[0];
mm[0] = mm[dir];
mm[dir] = i;
make_move(monptr, mm, rcmove);
/* this can only fail if mm[0] has a rune of protection */
}
/* if still in a wall, let it dig itself out, but also apply some more damage */
if (cave[m_ptr->fy][m_ptr->fx].fval >= MIN_CAVE_WALL) {
/* in case the monster dies, may need to call fix1_delete_monster()
* instead of delete_monsters()
*/
hack_monptr = monptr;
i = mon_take_hit(monptr, damroll(8, 8), FALSE);
hack_monptr = (-1);
if (i >= 0)
msg_print("You hear a scream muffled by rock!");
else
(void)twall((int)m_ptr->fy, (int)m_ptr->fx, 1, 0);
}
return; /* monster movement finished */
}
/* Creature is confused? Chance it becomes un-confused */
else if (m_ptr->confused) {
mm[0] = randint(9);
mm[1] = randint(9);
mm[2] = randint(9);
mm[3] = randint(9);
mm[4] = randint(9);
/* don't move him if he is not supposed to move! */
if (!(r_ptr->cmove & CM_ATTACK_ONLY)) {
*rcmove |= CM_ATTACK_ONLY;
make_move(monptr, mm, rcmove);
}
/* reduce conf, tough monsters can unconf faster -CFT */
{ /* use int so avoid unsigned wraparound -CFT */
int t = (int)m_ptr->confused;
t -= randint(c_list[m_ptr->mptr].level / 10);
if (t < 0)
t = 0;
m_ptr->confused = (int8u) t;
}
move_test = TRUE;
}
/* Creature may cast a spell */
else if (r_ptr->spells != 0) {
mon_cast_spell(monptr, &move_test);
}
if (!move_test) {
/* 75% random movement */
if ((r_ptr->cmove & CM_75_RANDOM) && (randint(100) < 75)) {
mm[0] = randint(9);
mm[1] = randint(9);
mm[2] = randint(9);
mm[3] = randint(9);
mm[4] = randint(9);
*rcmove |= CM_75_RANDOM;
make_move(monptr, mm, rcmove);
}
/* 40% random movement */
else if ((r_ptr->cmove & CM_40_RANDOM) && (randint(100) < 40)) {
mm[0] = randint(9);
mm[1] = randint(9);
mm[2] = randint(9);
mm[3] = randint(9);
mm[4] = randint(9);
*rcmove |= CM_40_RANDOM;
make_move(monptr, mm, rcmove);
}
/* 20% random movement */
else if ((r_ptr->cmove & CM_20_RANDOM) && (randint(100) < 20)) {
mm[0] = randint(9);
mm[1] = randint(9);
mm[2] = randint(9);
mm[3] = randint(9);
mm[4] = randint(9);
*rcmove |= CM_20_RANDOM;
make_move(monptr, mm, rcmove);
}
/* Normal movement */
else if (r_ptr->cmove & CM_MOVE_NORMAL) {
if (randint(200) == 1) {
mm[0] = randint(9);
mm[1] = randint(9);
mm[2] = randint(9);
mm[3] = randint(9);
mm[4] = randint(9);
} else
get_moves(monptr, mm);
*rcmove |= CM_MOVE_NORMAL;
make_move(monptr, mm, rcmove);
}
/* Attack, but don't move */
else if ((r_ptr->cmove & CM_ATTACK_ONLY) && (m_ptr->cdis < 2)) {
*rcmove |= CM_ATTACK_ONLY;
get_moves(monptr, mm);
make_move(monptr, mm, rcmove);
} else if ((r_ptr->cmove & CM_ALL_MV_FLAGS) == 0 &&
(m_ptr->cdis < 2)) {
/* little hack for Quylthulgs, so that will eventually notice
* that they have no physical attacks */
if (c_recall[m_ptr->mptr].r_attacks[0] < MAX_UCHAR)
c_recall[m_ptr->mptr].r_attacks[0]++;
}
}
}
/* Creatures movement and attacking are done from here -RAK- */
void
creatures(attack)
int attack;
{
register int i, k;
register monster_type *m_ptr;
recall_type *r_ptr;
int32u notice, rcmove;
int wake, ignore;
vtype cdesc;
/* Process the monsters */
for (i = mfptr - 1; i >= MIN_MONIX && !death; i--) {
m_ptr = &m_list[i];
/* Get rid of an eaten/breathed on monster. Note: Be sure not to process
* this monster. This is necessary because we can't delete monsters while
* scanning the m_list here.
*/
if (m_ptr->hp < 0) {
check_unique(m_ptr);
fix2_delete_monster(i);
continue;
}
m_ptr->cdis = distance(char_row, char_col,
(int)m_ptr->fy, (int)m_ptr->fx);
if (attack) { /* Attack is argument passed to CREATURE */
k = movement_rate(i);
if (k <= 0)
update_mon(i);
else
while (k > 0) {
k--;
wake = FALSE;
ignore = FALSE;
rcmove = 0;
if ((m_ptr->ml && /* check los so telepathy won't wake lice -CFT */
los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) ||
(m_ptr->cdis <= c_list[m_ptr->mptr].aaf)
/* Monsters trapped in rock must be given a turn also,
* so that they will die/dig out immediately. */
#ifdef ATARIST_MWC
|| ((!(c_list[m_ptr->mptr].cmove & (holder = CM_PHASE)))
#else
|| ((!(c_list[m_ptr->mptr].cmove & CM_PHASE))
#endif
&& cave[m_ptr->fy][m_ptr->fx].fval >= MIN_CAVE_WALL)) {
if (m_ptr->csleep > 0)
if (py.flags.aggravate)
m_ptr->csleep = 0;
else if ((py.flags.rest == 0 &&
py.flags.paralysis < 1)
|| (randint(50) == 1)) {
notice = randint(1024);
if ((notice * notice * notice) <=
(1L << (29 - py.misc.stl))) {
m_ptr->csleep -= (100 / m_ptr->cdis);
if (m_ptr->csleep > 0)
ignore = TRUE;
else {
wake = TRUE;
/* force it to be exactly zero */
m_ptr->csleep = 0;
}
}
}
if (m_ptr->stunned != 0) {
/* NOTE: Balrog = 100*100 = 10000, it always recovers instantly */
if (randint(5000) < c_list[m_ptr->mptr].level
* c_list[m_ptr->mptr].level)
m_ptr->stunned = 0;
else
m_ptr->stunned--;
if (m_ptr->stunned == 0) {
if (!m_ptr->ml)
(void)strcpy(cdesc, "It ");
else if (c_list[m_ptr->mptr].cdefense & UNIQUE)
(void)sprintf(cdesc, "%s ",
c_list[m_ptr->mptr].name);
else
(void)sprintf(cdesc, "The %s ",
c_list[m_ptr->mptr].name);
msg_print(strcat(cdesc,
"recovers and glares at you."));
}
}
if ((m_ptr->csleep == 0) && (m_ptr->stunned == 0))
mon_move(i, &rcmove);
}
update_mon(i);
if (m_ptr->ml) {
r_ptr = &c_recall[m_ptr->mptr];
if (wake) {
if (r_ptr->r_wake < MAX_UCHAR)
r_ptr->r_wake++;
} else if (ignore) {
if (r_ptr->r_ignore < MAX_UCHAR)
r_ptr->r_ignore++;
}
r_ptr->r_cmove |= rcmove;
}
}
} else
update_mon(i);
/* Get rid of an eaten/breathed on monster. This is necessary because we
* can't delete monsters while scanning the m_list here. This monster
* may have been killed during mon_move().
*/
if (m_ptr->hp < 0) {
check_unique(m_ptr);
fix2_delete_monster(i);
continue;
}
}
/* End processing monsters */
}
/* This is a fun one. In a given block, pick some walls and */
/* turn them into open spots. Pick some open spots and turn */
/* them into walls. An "Earthquake" effect. -LVB- */
static void
shatter_quake(mon_y, mon_x)
int mon_y, mon_x;
{
register int i, j, k, l;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
int kill, damage = 0, tmp, y, x = 0;
vtype out_val, m_name;
int monptr = cave[mon_y][mon_x].cptr;
/* needed when we kill another monster */
for (i = mon_y - 8; i <= mon_y + 8; i++)
for (j = mon_x - 8; j <= mon_x + 8; j++)
if (in_bounds(i, j) && (randint(8) == 1)) {
if ((i == mon_y) && (j == mon_x))
continue;
c_ptr = &cave[i][j];
if (c_ptr->cptr > 1) {
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
if (!(r_ptr->cmove & CM_PHASE) &&
!(r_ptr->cdefense & BREAK_WALL)) {
if ((movement_rate(c_ptr->cptr) == 0) ||
(r_ptr->cmove & CM_ATTACK_ONLY))
/* monster can not move to escape the wall */
kill = TRUE;
else {
/* only kill if there is nowhere for the monster to escape to */
kill = TRUE;
for (y = i - 1; y <= i + 1; y++) {
for (x = j - 1; x <= j + 1; x++) {
if ((cave[y][x].fval <= MAX_OPEN_SPACE) &&
!(y == i && x == j)) {
kill = FALSE;
break;
}
}
if (!kill)
break;
}
}
if (kill)
damage = 0x7fff; /* this will kill everything */
else
damage = damroll(4, 8);
monster_name(m_name, m_ptr, r_ptr);
(void)sprintf(out_val, "%s wails out in pain!", m_name);
msg_print(out_val);
/* kill monster "by hand", so player doesn't get exp -CFT */
m_ptr->hp = m_ptr->hp - damage;
m_ptr->csleep = 0;
/* prevent unique monster from death by other monsters. It causes trouble
* (monster not marked as dead, quest monsters don't satisfy quest, etc).
* So, we let then live, but extremely wimpy. This isn't great, because
* monster might heal itself before player's next swing... -CFT
*/
if ((r_ptr->cdefense & UNIQUE) && (m_ptr->hp < 0))
m_ptr->hp = 0;
if (m_ptr->hp < 0) {
int32u temp, treas;
(void)sprintf(out_val, "%s is embedded in the rock.",
m_name);
msg_print(out_val);
object_level = (dun_level + r_ptr->level) >> 1;
treas = monster_death((int)m_ptr->fy, (int)m_ptr->fx,
r_ptr->cmove, 0, 0);
if (m_ptr->ml) {
temp = (c_recall[m_ptr->mptr].r_cmove & CM_TREASURE)
>> CM_TR_SHIFT;
if (temp > ((treas & CM_TREASURE) >> CM_TR_SHIFT))
treas = (treas & ~CM_TREASURE) | (temp << CM_TR_SHIFT);
c_recall[m_ptr->mptr].r_cmove = treas |
(c_recall[m_ptr->mptr].r_cmove & ~CM_TREASURE);
}
if (monptr < c_ptr->cptr)
delete_monster((int)c_ptr->cptr);
else
fix1_delete_monster((int)c_ptr->cptr);
} /* if monster's hp < 0 */
}
} else if (c_ptr->cptr == 1) { /* Kill the dumb player! */
kill = TRUE;
for (y = i - 1; y <= i + 1; y++) {
for (x = j - 1; x <= j + 1; x++) {
if ((cave[y][x].fval <= MAX_OPEN_SPACE) &&
(cave[y][x].cptr == 0) && !(y == i && x == j)) {
kill = FALSE;
break;
}
}
if (!kill)
break;
}
switch (randint(3)) {
case 1:
msg_print("The cave ceiling collapses!");
break;
case 2:
msg_print("The floor turns and crushes you!");
break;
case 3:
msg_print("You are pummeled with debris!");
break;
}
if (kill) {
msg_print("You are trapped and cannot move! You are crushed beneath rock!");
msg_print(NULL);
damage = 320;
} else {
switch (randint(3)) {
case 1:
msg_print("The rubble bashes you!");
damage = damroll(10, 4);
stun_player(randint(50));
break;
case 2:
msg_print("But you nimbly dodge the blast!");
damage = 0;
break;
case 3:
msg_print("The floor crushes you against the ceiling!");
damage = damroll(10, 4);
stun_player(randint(50));
break;
}
move_rec(char_row, char_col, y, x);
for (k = char_row - 1; k <= char_row + 1; k++)
for (l = char_col - 1; l <= char_col + 1; l++) {
c_ptr = &cave[k][l];
c_ptr->tl = FALSE;
lite_spot(k, l);
}
lite_spot(char_row, char_col);
char_row = y;
char_col = x;
check_view();
/* light creatures */
creatures(FALSE);
}
take_hit(damage, "an Earthquake");
}
if (c_ptr->tptr != 0)
if (((t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
(t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) ||
(t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
(t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) ||
(t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
continue; /* don't kill artifacts... */
else
(void)delete_object(i, j);
if ((c_ptr->fval >= MIN_CAVE_WALL) && (c_ptr->fval != BOUNDARY_WALL)) {
c_ptr->fval = CORR_FLOOR;
c_ptr->pl = FALSE;
c_ptr->fm = FALSE;
} else if ((c_ptr->fval <= MAX_CAVE_FLOOR) && (c_ptr->tptr == 0)
&& (c_ptr->cptr != 1)) {
/* don't bury player, it made him unattackable -CFT */
tmp = randint(10);
if (tmp < 6)
c_ptr->fval = QUARTZ_WALL;
else if (tmp < 9)
c_ptr->fval = MAGMA_WALL;
else
c_ptr->fval = GRANITE_WALL;
c_ptr->fm = FALSE;
}
lite_spot(i, j);
}
}
/* This is a fun one. In a given block, pick some walls and */
/* turn them into open spots. Pick some open spots and turn */
/* them into walls. An "Earthquake" effect. -LVB- */
static void
br_wall(mon_y, mon_x)
int mon_y, mon_x;
{
register int k, l;
register cave_type *c_ptr;
int kill, damage = 0, tmp, y, x = 0;
kill = TRUE;
for (y = char_row - 1; y <= char_row + 1; y++) {
for (x = char_col - 1; x <= char_col + 1; x++) {
if ((cave[y][x].fval <= MAX_OPEN_SPACE) &&
(cave[y][x].cptr == 0) && !(y == char_row && x == char_col)) {
kill = FALSE;
break;
}
}
if (!kill)
break;
}
switch (randint(3)) {
case 1:
msg_print("The cave ceiling collapses!");
break;
case 2:
msg_print("The floor turns and crushes you!");
break;
case 3:
msg_print("You are pummeled with debris!");
break;
}
if (kill) {
msg_print("You are trapped, crushed and cannot move!");
damage = 250;
} else {
switch (randint(3)) {
case 1:
msg_print("The rubble bashes you!");
damage = damroll(10, 4);
stun_player(randint(50));
break;
case 2:
msg_print("But you nimbly dodge the blast!");
damage = 0;
break;
case 3:
msg_print("The floor crushes you against the ceiling!");
damage = damroll(10, 4);
stun_player(randint(50));
break;
}
c_ptr = &cave[char_row][char_col];
move_rec(char_row, char_col, y, x);
/* don't destroy floor if stairs, shop, or artifact... */
if ((c_ptr->fval <= MAX_CAVE_FLOOR) &&
((c_ptr->tptr == 0) || ((t_list[c_ptr->tptr].tval != TV_UP_STAIR) &&
(t_list[c_ptr->tptr].tval != TV_DOWN_STAIR) &&
(t_list[c_ptr->tptr].tval != TV_STORE_DOOR) &&
!((t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
(t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT))))) {
if (c_ptr->tptr)
delete_object(char_row, char_col);
tmp = randint(10);
if (tmp < 6)
c_ptr->fval = QUARTZ_WALL;
else if (tmp < 9)
c_ptr->fval = MAGMA_WALL;
else
c_ptr->fval = GRANITE_WALL;
c_ptr->fm = FALSE;
}
for (k = char_row - 1; k <= char_row + 1; k++)
for (l = char_col - 1; l <= char_col + 1; l++) {
c_ptr = &cave[k][l];
c_ptr->tl = FALSE;
lite_spot(k, l);
}
lite_spot(char_row, char_col);
char_row = y;
char_col = x;
} /* !kill */
check_view();
/* light creatures */
creatures(FALSE);
lite_spot(char_row, char_col);
take_hit(damage, "an Earthquake");
}